package com.zhou.framework.quartz.common;

import com.zhou.util.PropertyUtil;
import com.zhou.framework.exception.QuartzException;
import com.zhou.framework.quartz.model.JobConfig;
import org.quartz.*;

import java.util.Map;
import java.util.Properties;

/**
 * 定时任务管理（需要提供事务控制）
 * @author lang.zhou
 * @date 2019/12/21
 */
public class SchedulerManager {
    private Scheduler scheduler = null;
    public SchedulerManager(){
        scheduler = SchedulerFactory.createScheduler();
    }
    public SchedulerManager(Scheduler scheduler){
        this.scheduler = scheduler;
    }

    public SchedulerManager(Properties property) throws Exception {
        this.scheduler = SchedulerFactory.createScheduler(property);
        String listenerClassPath = PropertyUtil.getStringValue("quartz.properties","com.zhou.quartz.listener","");
        if(listenerClassPath.length() > 0){
            Class c = Class.forName(listenerClassPath);
            Object listener = c.newInstance();
            if(listener instanceof TriggerListener){
                this.scheduler.getListenerManager().addTriggerListener((TriggerListener)listener);
            }
            if(listener instanceof JobListener){
                this.scheduler.getListenerManager().addJobListener((JobListener)listener);
            }

        }
    }
    public void start() throws SchedulerException {
        if(!scheduler.isStarted()){
            scheduler.start();
        }
    }
    public void pause() throws SchedulerException {
        if(scheduler.isStarted()){
            scheduler.pauseAll();
        }
    }
    public void stop() throws SchedulerException {
        if(!scheduler.isShutdown()){
            scheduler.shutdown(true);
        }
    }
    public void createJob(JobConfig config) throws SchedulerException {
        createJob(config, null);
    }
    /**
     * 添加一个定时任务，使用默认的任务组名，触发器名，触发器组名（可带参数）
     */
    public synchronized void createJob(JobConfig config,Map<String, Object> param) throws SchedulerException {
        JobConfigCheck.check(config);
        // 任务名，任务组，任务执行类
        JobDetail jobDetail = JobBuilder.newJob(config.getClazz()).withIdentity(config.getJobName(), config.getJobGroupName()).build();
        // 传参数
        if(param != null && !param.isEmpty()){
            jobDetail.getJobDataMap().put("parameterList", param);
        }
        // 触发器
        CronTrigger trigger = this.createTrigger(config);
        //scheduler.addJob(jobDetail, true);
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.rescheduleJob(TriggerKey.triggerKey(config.getTriggerName(), config.getTriggerGroupName()), trigger);
    }
    /**
     * 修改一个任务的触发时间(使用默认的任务组名，触发器名，触发器组名)
     */
    public synchronized void updateJob(JobConfig config,Map<String, Object> param) throws SchedulerException {
        // 先删除，后增加
        deleteJob(config);
        createJob(config,param);
    }

    /**
     * 暂停定时任务
     */
    public synchronized void pauseJob(JobConfig config) throws SchedulerException {
        JobConfigCheck.check(config);
        TriggerKey triggerKey = TriggerKey.triggerKey(config.getTriggerName(), config.getTriggerGroupName());
        scheduler.pauseTrigger(triggerKey);
        JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
        scheduler.pauseJob(jobKey);
    }

    /**
     * 恢复定时任务
     */
    public synchronized void resumeJob(JobConfig config) throws SchedulerException {
        JobConfigCheck.check(config);
        TriggerKey triggerKey = TriggerKey.triggerKey(config.getTriggerName(), config.getTriggerGroupName());
        scheduler.resumeTrigger(triggerKey);
        JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
        scheduler.resumeJob(jobKey);
    }

    /**
     * 删除触发器
     */
    public void deleteTrigger(String triggerName,String triggerGroupName) throws SchedulerException {
        // 通过触发器名和组名获取TriggerKey
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
        // 停止触发器
        scheduler.pauseTrigger(triggerKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
    }

    /**
     * 修改频率
     */
    public void changeTrigger(JobConfig config) throws SchedulerException {
        JobConfigCheck.check(config);
        JobDetail job = this.getJobDetail(config);
        if(job != null){
            deleteTrigger(config.getTriggerName(),config.getTriggerGroupName());
            createTrigger(config);
        }
    }
    public JobDetail getJobDetail(JobConfig config) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
        return scheduler.getJobDetail(jobKey);
    }
    public CronTrigger getTrigger(JobConfig config) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(config.getTriggerName(), config.getTriggerGroupName());
        return (CronTrigger) scheduler.getTrigger(triggerKey);
    }
    private CronTrigger createTrigger(JobConfig config) throws SchedulerException {
        if(this.getTrigger(config) != null){
            throw new QuartzException("触发器["+config.getTriggerGroupName()+" - "+config.getTriggerName()+"]已存在！");
        }
        CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(config.getCron()).withMisfireHandlingInstructionDoNothing();
        //暂停恢复后，不补偿未执行时间的次数
        schedBuilder.withMisfireHandlingInstructionDoNothing();
        return TriggerBuilder
                .newTrigger().withSchedule(schedBuilder).withIdentity(config.getTriggerName(),config.getTriggerGroupName()).build();
    }
    private JobDetail createJobDetail(JobConfig config) throws SchedulerException {
        if(this.getJobDetail(config) != null){
            throw new QuartzException("定时任务["+config.getJobGroupName()+" - "+config.getJobName()+"]已存在！");
        }
        return JobBuilder.newJob(config.getClazz()).withIdentity(config.getJobName(), config.getJobGroupName()).build();
    }
    /**
     * 移除一个任务(使用默认的任务组名，触发器名，触发器组名)
     */
    public synchronized void deleteJob(JobConfig config) throws SchedulerException {
        JobConfigCheck.check(config);
        // 通过任务名和组名获取JobKey
        JobKey jobKey = JobKey.jobKey(config.getJobName(), config.getJobGroupName());
        deleteTrigger(config.getTriggerName(),config.getTriggerGroupName());
        // 删除任务
        scheduler.deleteJob(jobKey);
    }
    public Scheduler getScheduler(){
        return scheduler;
    }
}
